package enron.Generator;

import java.util.ArrayList;

import enron.VendorAgent;

public abstract class Generator {
	
	protected class CapacityBelowMinimumException extends Exception {
		private static final long serialVersionUID = -2628190550800221056L;
		
		CapacityBelowMinimumException(Generator myGenerator, Long reduction) {
			super(myGenerator.name + "(" + myGenerator.getClass().getName() + "): " + myGenerator.getCurrentSupply() + "(Current Capacity) - " + reduction + " = " + (myGenerator.getCurrentSupply() - reduction) + " < " + myGenerator.getMinimumSupply() + "(Minimum Capacity)");
		}
	}
	
	protected Long startUpTime = 0L;     //In Minutes
	private VendorAgent myAgent;
	private Long maximumSupply = 0L; //In kW
	private Long minimumSupply = 0L; //In kW
	protected String name;
	
	private Long currentSupply = 0L; //In kW


	public Generator(VendorAgent agent, String newName, Long max, Long min, Long startup) {
		setAgent(agent);
		name = newName;
		startUpTime = startup;
		maximumSupply = max;
		minimumSupply = min;
		currentSupply = max;

		if(myAgent != null) {
	        myAgent.changePower(this.currentSupply);
		}
	}

	public Generator(VendorAgent agent, String newName, ArrayList<Object> args) {
		this(agent, newName, (Long) args.get(0),(Long) args.get(1),(Long) args.get(2));
	}

	public Generator(String newName, Long max, Long min, Long startup) {
		this(null, newName, max,min,startup);
	}

	public Double getTurnOffCost() {
		return startUpTime/6.0;
	}
	
	public void turnDown(Long reductionAmount) {
		if((currentSupply - reductionAmount) >= minimumSupply) {
			myAgent.changePower(-reductionAmount);
			currentSupply -= reductionAmount;
		} else {
//			System.out.print((currentSupply - reductionAmount));
			turnOff();
		}
	}

	private void turnUp(long increaseAmount) {
		if((currentSupply + increaseAmount) <= maximumSupply) {
			myAgent.changePower(+increaseAmount);
			currentSupply += increaseAmount;
		} else {
			myAgent.changePower(maximumSupply - currentSupply);
			currentSupply = maximumSupply;
		}
	}
	
	public void turnOff() {
		myAgent.changePower(-currentSupply);
		currentSupply = 0L;
	}
	
	abstract public Double getTurnDownCost(Long reductionAmount);

	public String getDisplay() {
		return name;
	}

	public Long getCurrentSupply() {
		return currentSupply;
	}

	public void setCurrentSupply(Long currentSupply) {
		this.currentSupply = currentSupply;
	}

	public void adjustSupplyTo(Long value) {
		Long powerDiff = value - currentSupply;
		adjustSupplyBy(powerDiff);
	}
	
	public boolean adjustSupplyBy(Long powerAdj) {
		boolean returnVal = false;
		if(Math.abs(powerAdj) > maximumSupply) {
			returnVal = false;
		} else if(powerAdj == 0) {
//			System.out.println(" diff is 0 ");
			returnVal = true;
		} else if(powerAdj < 0 && ((currentSupply + powerAdj) >= minimumSupply)) {
//			System.out.println("Turning down because " + (currentSupply + powerAdj) + ">=" + minimumSupply); 
			turnDown(-powerAdj);
			returnVal =  true;
		} else if(powerAdj > 0 && ((currentSupply + powerAdj) <= maximumSupply)) {
//			System.out.println("Turning up because " + (currentSupply + powerAdj) + "<=" + maximumSupply);
			turnUp(powerAdj);
			returnVal =  true;
		} else {
//			System.out.println("Problem with adjustment: current(" + currentSupply + "), max(" + maximumSupply + "), min(" + minimumSupply + "), adjustment(" + powerAdj + ")");
			returnVal = false;
		}
		return returnVal;
	}

	public Long getMinimumSupply() {
		return minimumSupply;
	}

	public void setMinimumSupply(Long minimumSupply) {
		this.minimumSupply = minimumSupply;
	}

	public Long getMaximumSupply() {
		return maximumSupply;
	}

	public void setMaximumSupply(Long maximumSupply) {
		this.maximumSupply = maximumSupply;
	}

	public VendorAgent getMyAgent() {
		return myAgent;
	}

	public void setAgent(VendorAgent myAgent) {
		this.myAgent = myAgent;
	}
}
